package com.jasic.comnt.protocol.bean;

import com.jasic.common.exception.HandleException;
import com.jasic.comnt.protocol.MessageCommon;
import com.jasic.util.ProtocolUtil;

/**
 * User: Jasic
 * Date: 12-12-24
 */
public abstract class BasePacket {

    /**
     * This common message, every data been must contain it...
     */
    private MessageCommon common;

    /**
     * This byte array load some data about types of message detail
     */
    byte[] msgByte;

    /**
     * Client side used
     *
     * @param common
     */
    public BasePacket(MessageCommon common) {
        this.common = common;
    }

    protected void initCheckNum() {

        if (common.getCheckNum() != 0x00) return;

        byte[] bytes = new byte[4];
        bytes[0] = common.getLength();
        bytes[1] = common.getCmd();
        bytes[2] = common.getQuestion();
        bytes[3] = common.getAnswer();

        byte[] msgBytes = getMsgByte();
        byte[] allBytes = new byte[bytes.length + msgBytes.length];
        System.arraycopy(bytes, 0, allBytes, 0, bytes.length);
        System.arraycopy(msgBytes, 0, allBytes, bytes.length, msgBytes.length);

        // As we know that 0 xor any other number equal the number itselft
        byte checkNum = 0x00;
        for (byte b : allBytes) {
            checkNum ^= b;
        }

        this.common.setCheckNum(checkNum);
    }

    protected abstract byte[] getMsgByte();

    /**
     * get the actually byte data...
     *
     * @return
     */
    public byte[] toByte() {

        byte[] msgByte = getMsgByte();

        // exclude head and tail
        int length = common.length() + msgByte.length - 2;

        byte[] actulData = new byte[length];

        actulData[0] = common.getLength();
        actulData[1] = common.getCmd();
        actulData[2] = common.getQuestion();
        actulData[3] = common.getAnswer();

        System.arraycopy(msgByte, 0, actulData, 4, msgByte.length);

        byte[] wrappedByte = ProtocolUtil.wrapRequestData(actulData);

        byte[] protocolData = new byte[wrappedByte.length + 2];
        protocolData[0] = common.getHeader();
        protocolData[protocolData.length - 1] = common.getTail();

        System.arraycopy(wrappedByte, 0, protocolData, 1, wrappedByte.length);
        return protocolData;
    }

    /**
     * Server side used...
     *
     * @param data
     */
    public BasePacket(byte[] data) throws HandleException{
        this.common = toMessageCommon(data);
        this.setValues();
    }

    protected abstract void setValues() throws HandleException;

    private MessageCommon toMessageCommon(byte[] data) {

        // 获取头与尾
        byte header = data[0];
        byte tail = data[data.length - 1];

        byte[] protocolData = new byte[data.length - 2];
        System.arraycopy(data, 1, protocolData, 0, protocolData.length);
        byte[] actualData = ProtocolUtil.unWrapRequestData(protocolData);

        byte length = actualData[0];

        // Data -- command
        byte cmd = actualData[1];

        // Who i am
        byte question = actualData[2];

        // Is that you
        byte answer = actualData[3];

        // Check number the last is :length -1
        byte checkNum = actualData[actualData.length - 1];

        this.msgByte = new byte[actualData.length - 5];
        System.arraycopy(actualData, 4, msgByte, 0, msgByte.length);
        return new MessageCommon(header, length, cmd, question, answer, tail);
    }
}
